/*******************************************************************************************
This file is part of iToday.

iToday is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

iToday is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with iToday.  If not, see <http://www.gnu.org/licenses/>.
* ------------------------------------------------------------------------------
*    PicturePanel.cpp - Class PicturePanel implement
* ------------------------------------------------------------------------------
*    Revision History
*    Date                  Author         Activity ID               Activity Headline
*    2009-10-13            Congqin				none						initial
*******************************************************************************************/

#include "stdafx.h"

#include <imaging.h>
#include <imgguids.h>

#include "PicturePanel.h"
#include "LogUtility.h"

static HPHYSICSENGINE g_hPhysicsEngine = NULL;

TCHAR* pPhotoFile[]=
{
    RES_PATH("1.jpg"),
    RES_PATH("2.jpg"),
    RES_PATH("3.jpg"),
    RES_PATH("4.jpg"),
    RES_PATH("5.jpg"),
    RES_PATH("6.jpg"),
    RES_PATH("7.jpg"),
    RES_PATH("8.jpg"),
    RES_PATH("9.jpg"),
    RES_PATH("10.jpg"),
    RES_PATH("11.jpg"),
    RES_PATH("1.jpg"),
    RES_PATH("2.jpg"),
    RES_PATH("3.jpg"),
    RES_PATH("4.jpg"),
    RES_PATH("5.jpg"),
    RES_PATH("6.jpg"),
    RES_PATH("7.jpg"),
    RES_PATH("8.jpg"),
    RES_PATH("9.jpg"),
    RES_PATH("10.jpg"),
    RES_PATH("11.jpg"),
    RES_PATH("1.jpg"),
    RES_PATH("2.jpg"),
    RES_PATH("3.jpg"),
    RES_PATH("4.jpg"),
    RES_PATH("5.jpg"),
    RES_PATH("6.jpg"),
    RES_PATH("7.jpg"),
    RES_PATH("8.jpg"),
    RES_PATH("9.jpg"),
    RES_PATH("10.jpg"),
    RES_PATH("11.jpg"),

};

PicturePanel::PicturePanel()
{
    EMPTYPOINT( m_ptStartPointInMemDC);
}

BOOL PicturePanel::InitMemoryDC()
{
    m_hMemoryDC = CreateCompatibleDC( m_hRealDC );
    if ( NULL == m_hMemoryDC )
    {
        Logger::Instance().Log( LOG_TRACE, L"create the m_hMemoryDC is failure! " );
        return FALSE;
    }
    m_hMemoryDC_Height = ( ( m_rcScreen.bottom - m_rcScreen.right/5 )/5 +
                           ( m_rcScreen.bottom - m_rcScreen.right/5 )/50  )  *
                         ( SIZEBUFFER(pPhotoFile)/3 + SIZEBUFFER(pPhotoFile)%2 + 1 )
                         +( m_rcScreen.bottom - m_rcScreen.right/5 )/50;

    //Logger::Instance().Log( LOG_TRACE, L"Thread1: PicturePanel::InitMemoryDC: Picture Memory Height is %d\n", m_hMemoryDC_Height );
    m_nMaxXExtent = 0;
    m_nMaxYExtent = m_hMemoryDC_Height - HEIGHT(m_rcScreen);

    if ( m_hMemoryDC_Height < m_rcScreen.bottom )
        m_hMemoryDC_Height = m_rcScreen.bottom ;
    m_hMemoryBm = CreateCompatibleBitmap( m_hRealDC,m_rcScreen.right ,m_hMemoryDC_Height );
    if ( NULL == m_hMemoryBm )
    {
        Logger::Instance().Log( LOG_TRACE, L"Thread1: PicturePanel::InitMemoryDC: create the m_hMemoryBm is failure!\n " );
        return FALSE;
    }
    SelectObject( m_hMemoryDC, m_hMemoryBm );

    DrawMemoryDC();

    return TRUE;

}

void PicturePanel::DrawMemoryDC()
{
    RECT rc={0,0,0,0};
    HBRUSH hBrush;

    hBrush  = (HBRUSH)GetStockObject (WHITE_BRUSH) ;
    SelectObject (m_hRealDC, hBrush);

    long lTmep = m_rcScreen.right *3/10 ;

    DrawImageClass*  drawDC = new DrawImageClass();

    for ( int i=0; i < SIZEBUFFER(pPhotoFile); i++ )
    {
        rc.left		= lTmep * (i%3) + m_rcScreen.right/40 * ( i%3 + 1 );
        rc.right	= lTmep + rc.left;
        rc.top		= ( m_rcScreen.bottom - m_rcScreen.right/5 )/5*(i/3) +
                  ( m_rcScreen.bottom - m_rcScreen.right/5 )/50*(1+i/3);
        rc.bottom	= ( m_rcScreen.bottom - m_rcScreen.right/5 )/5 + rc.top;

        FillRect( m_hMemoryDC, &rc, hBrush );

        rc.left		= rc.left + lTmep/20;
        rc.right	= rc.right - lTmep/20;
        rc.bottom	= rc.bottom - lTmep/20;
        rc.top		= rc.top + lTmep/20;

        drawDC ->DrawImageToDC ( m_hMemoryDC, rc, pPhotoFile[i] );
        Logger::Instance().Log( LOG_TRACE, L"Thread1: PicturePanel::DrawMemoryDC: have drawn %i Images\n", i+1);

    }

    delete drawDC;
    DeleteObject(hBrush);

    return;
}


BOOL PicturePanel::Draw()
{
    BitBlt(m_hPublicMemoryDC,
           0,
           0,
           m_rcScreen.right,
           m_rcScreen.bottom - m_rcScreen.right/5,
           m_hMemoryDC,
           0,
           0,
           SRCCOPY
          );

    return TRUE;

}

PicturePanel::~PicturePanel()
{
    DELETE_OBJ(m_hMemoryDC);
    DELETE_OBJ(m_hMemoryBm);
}

void PicturePanel::SnapBackToFrame()
{
    m_ptStartPointInMemDC.x = max(m_ptStartPointInMemDC.x, 0);
    m_ptStartPointInMemDC.y = max(m_ptStartPointInMemDC.y, 0);
    m_ptStartPointInMemDC.x = min(m_ptStartPointInMemDC.x, m_nMaxXExtent);
    m_ptStartPointInMemDC.y = min(m_ptStartPointInMemDC.y, m_nMaxYExtent);

    BitBlt( m_hRealDC, 0, 0,
            m_rcScreen.right, m_rcScreen.bottom - m_rcScreen.right/5 ,
            m_hMemoryDC,
            m_ptStartPointInMemDC.x, m_ptStartPointInMemDC.y,
            SRCCOPY
          );

    KillTimer(g_hWnd, m_uAnimationTimerId);
    // its safe to pass a null here
    (void) TKDestroyPhysicsEngine(g_hPhysicsEngine);
    g_hPhysicsEngine = NULL;
}

HRESULT PicturePanel::ProcessPanEnd( int nTransitionSpeed, DWORD nTransitionAngle )
{
    HRESULT hr = S_OK;
    int nYExtendedPan = 0;
    int nXExtendedPan = 0;
    PHYSICSENGINEINIT initState = {sizeof(initState)};
    RECT rctClient = {0};

    if (0> m_ptStartPointInMemDC.y)
    {
        nYExtendedPan = m_ptStartPointInMemDC.y;
    }
    else if ( m_nMaxYExtent < m_ptStartPointInMemDC.y)
    {
        nYExtendedPan = m_ptStartPointInMemDC.y - m_nMaxYExtent;
    }

    initState.dwEngineType              = 0;
    initState.dwFlags                   = 0;
    initState.lInitialVelocity          = -nTransitionSpeed;
    initState.dwInitialAngle            = nTransitionAngle;
    initState.bXAxisMovementMode        = PHYSICSENGINE_MOVEMENT_MODE_DECELERATE;
    initState.bYAxisMovementMode        = PHYSICSENGINE_MOVEMENT_MODE_DECELERATE;
    initState.bXAxisBoundaryMode        = PHYSICSENGINE_BOUNDARY_MODE_RUBBERBAND;
    initState.bYAxisBoundaryMode        = PHYSICSENGINE_BOUNDARY_MODE_RUBBERBAND;
    GetClientRect(g_hWnd, &rctClient);
    initState.rcBoundary.left           = 0;
    initState.rcBoundary.right          = rctClient.right + m_nMaxXExtent;
    initState.rcBoundary.top            = 0;
    initState.rcBoundary.bottom         = rctClient.bottom + m_nMaxYExtent;
    initState.sizeView.cx               = rctClient.right;
    initState.sizeView.cy               = rctClient.bottom;
    initState.ptInitialPosition.x       = m_ptStartPointInMemDC.x;
    initState.ptInitialPosition.y       = m_ptStartPointInMemDC.y;
    initState.sizeItem.cx               = 1;
    initState.sizeItem.cy               = 1;

    // create the physics engine and store it
    if (SUCCEEDED(TKCreatePhysicsEngine(&initState, &g_hPhysicsEngine)))
    {
        // Setup the timer
        m_uAnimationTimerId = SetTimer( g_hWnd,
                                        GESTURE_ANIMATION_TIMER_ID,
                                        GESTURE_ANIMATION_FRAME_REFRESH_MS,
                                        NULL);
    }

    return hr;
}

BOOL PicturePanel::ProcessPan(POINTS& pt)
{
    m_ptStartPointInMemDC.y  =  m_ptStartPointInMemDC.y - (pt.y - m_ptLastPan.y);

    FillEmptyPlaceWithBlack();

    return BitBlt( m_hRealDC, 0, 0, m_rcScreen.right, m_rcScreen.bottom - m_rcScreen.right/5 ,
                   m_hMemoryDC, m_ptStartPointInMemDC.x, m_ptStartPointInMemDC.y,
                   SRCCOPY
                 );
}

BOOL PicturePanel::ProcessAnimationTimer()
{
    PHYSICSENGINESTATE state = {sizeof(state)};

    if ( NULL == g_hPhysicsEngine)
    {
        SnapBackToFrame();
        Logger::Instance().Log( LOG_TRACE, L"PicturePanel::ProcessAnimationTimer: Invalid state in timer callback\n");
        MessageBox(g_hWnd, TEXT("Error"), TEXT("Invalid state in timer callback"), MB_OK);
        return FALSE;
    }

    TKQueryPhysicsEngine(g_hPhysicsEngine, &state);

    m_ptStartPointInMemDC.x = state.ptPosition.x;
    m_ptStartPointInMemDC.y = state.ptPosition.y;

    BitBlt( m_hRealDC, 0, 0,
            m_rcScreen.right, m_rcScreen.bottom - m_rcScreen.right/5,
            m_hMemoryDC,
            m_ptStartPointInMemDC.x, m_ptStartPointInMemDC.y,
            SRCCOPY
          );
    FillEmptyPlaceWithBlack();

    // If the animation is now complete we need to clean up all our resources.
    // Just to be safe this is done by calling Snap to ensure there is no residual offset
    if (state.fComplete)
    {
        // pPanState here should be valid still (even tho PanAxis can release it) because
        // the fAnimating flag is guaranteed to be set at this point
        SnapBackToFrame();
    }

    return TRUE;
}

BOOL PicturePanel::RecordLastPanPoint( POINTS& pt )
{
    m_ptLastPan.x = pt.x ;
    m_ptLastPan.y = pt.y ;
    return TRUE ;
}

BOOL PicturePanel::CalculateStartPointInMemDC( POINTS& pt )
{
    m_ptStartPointInMemDC.x -= (pt.x - m_ptLastPan.x);
    m_ptStartPointInMemDC.y -= (pt.y - m_ptLastPan.y);
    return TRUE;
}

void PicturePanel::FillEmptyPlaceWithBlack()
{
    // Check for any 'black' space
    if (m_ptStartPointInMemDC.x < 0)
    {
        RECT rc =
        {
            m_rcScreen.left,
            m_rcScreen.top,
            abs(m_ptStartPointInMemDC.x),
            m_rcScreen.bottom - m_rcScreen.right/5
        };

        BitBlt( m_hRealDC,
                rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
                m_hMemoryDC,
                0 , 0,
                BLACKNESS);
    }

    if (m_ptStartPointInMemDC.y < 0)
    {
        RECT rc =
        {
            m_rcScreen.left,
            m_rcScreen.top,
            m_rcScreen.right,
            abs(m_ptStartPointInMemDC.y)
        };

        BitBlt( m_hRealDC,
                rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
                m_hMemoryDC,
                0, 0,
                BLACKNESS);
    }

    if (m_ptStartPointInMemDC.x > m_nMaxXExtent)
    {
        RECT rc =
        {
            m_rcScreen.right - (m_ptStartPointInMemDC.x - m_nMaxXExtent),
            m_rcScreen.top,
            m_rcScreen.right,
            m_rcScreen.bottom - m_rcScreen.right/5
        };

        BitBlt( m_hRealDC,
                rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
                m_hMemoryDC,
                0, 0,
                BLACKNESS);
    }

    if (m_ptStartPointInMemDC.y > m_nMaxYExtent)
    {
        RECT rc =
        {
            m_rcScreen.left,
            m_rcScreen.bottom - (m_ptStartPointInMemDC.y - m_nMaxYExtent),
            m_rcScreen.right,
            m_rcScreen.bottom - m_rcScreen.right/5
        };

        BitBlt( m_hRealDC,
                rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
                m_hMemoryDC,
                0, 0,
                BLACKNESS);
    }
}